/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package it.polimi.games.epkb.controller;

import it.polimi.games.epkb.controller.exceptions.IllegalOrphanException;
import it.polimi.games.epkb.controller.exceptions.NonexistentEntityException;
import it.polimi.games.epkb.controller.exceptions.PreexistingEntityException;
import java.io.Serializable;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Query;
import javax.persistence.EntityNotFoundException;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import it.polimi.games.epkb.entityClasses.Component;
import it.polimi.games.epkb.entityClasses.Service;
import java.util.ArrayList;
import java.util.Collection;
import it.polimi.games.epkb.entityClasses.Activity;
import it.polimi.games.epkb.entityClasses.VirtualMachineConf;
import it.polimi.games.epkb.entityClasses.ServiceInstance;
import javax.transaction.UserTransaction;

/**
 *
 * @author plebani
 */
public class ServiceJpaController implements Serializable {

    public ServiceJpaController(EntityManagerFactory emf) {
        this.utx = null;
        this.emf = emf;
    }

    public ServiceJpaController(UserTransaction utx, EntityManagerFactory emf) {
        this.utx = utx;
        this.emf = emf;
    }
    private UserTransaction utx = null;
    private EntityManagerFactory emf = null;

    public EntityManager getEntityManager() {
        return emf.createEntityManager();
    }

    public void create(Service service) throws IllegalOrphanException, PreexistingEntityException, Exception {
        if (service.getServiceCollection() == null) {
            service.setServiceCollection(new ArrayList<Service>());
        }
        if (service.getServiceCollection1() == null) {
            service.setServiceCollection1(new ArrayList<Service>());
        }
        if (service.getActivityCollection() == null) {
            service.setActivityCollection(new ArrayList<Activity>());
        }
        if (service.getVirtualMachineConfCollection() == null) {
            service.setVirtualMachineConfCollection(new ArrayList<VirtualMachineConf>());
        }
        if (service.getServiceInstanceCollection() == null) {
            service.setServiceInstanceCollection(new ArrayList<ServiceInstance>());
        }
        List<String> illegalOrphanMessages = null;
        Component componentOrphanCheck = service.getComponent();
        if (componentOrphanCheck != null) {
            Service oldServiceOfComponent = componentOrphanCheck.getService();
            if (oldServiceOfComponent != null) {
                if (illegalOrphanMessages == null) {
                    illegalOrphanMessages = new ArrayList<String>();
                }
                illegalOrphanMessages.add("The Component " + componentOrphanCheck + " already has an item of type Service whose component column cannot be null. Please make another selection for the component field.");
            }
        }
        if (illegalOrphanMessages != null) {
            throw new IllegalOrphanException(illegalOrphanMessages);
        }
        EntityManager em = null;
        try {
            em = getEntityManager();
            em.getTransaction().begin();
            Component component = service.getComponent();
            if (component != null) {
                component = em.getReference(component.getClass(), component.getId());
                service.setComponent(component);
            }
            Collection<Service> attachedServiceCollection = new ArrayList<Service>();
            for (Service serviceCollectionServiceToAttach : service.getServiceCollection()) {
                serviceCollectionServiceToAttach = em.getReference(serviceCollectionServiceToAttach.getClass(), serviceCollectionServiceToAttach.getId());
                attachedServiceCollection.add(serviceCollectionServiceToAttach);
            }
            service.setServiceCollection(attachedServiceCollection);
            Collection<Service> attachedServiceCollection1 = new ArrayList<Service>();
            for (Service serviceCollection1ServiceToAttach : service.getServiceCollection1()) {
                serviceCollection1ServiceToAttach = em.getReference(serviceCollection1ServiceToAttach.getClass(), serviceCollection1ServiceToAttach.getId());
                attachedServiceCollection1.add(serviceCollection1ServiceToAttach);
            }
            service.setServiceCollection1(attachedServiceCollection1);
            Collection<Activity> attachedActivityCollection = new ArrayList<Activity>();
            for (Activity activityCollectionActivityToAttach : service.getActivityCollection()) {
                activityCollectionActivityToAttach = em.getReference(activityCollectionActivityToAttach.getClass(), activityCollectionActivityToAttach.getId());
                attachedActivityCollection.add(activityCollectionActivityToAttach);
            }
            service.setActivityCollection(attachedActivityCollection);
            Collection<VirtualMachineConf> attachedVirtualMachineConfCollection = new ArrayList<VirtualMachineConf>();
            for (VirtualMachineConf virtualMachineConfCollectionVirtualMachineConfToAttach : service.getVirtualMachineConfCollection()) {
                virtualMachineConfCollectionVirtualMachineConfToAttach = em.getReference(virtualMachineConfCollectionVirtualMachineConfToAttach.getClass(), virtualMachineConfCollectionVirtualMachineConfToAttach.getId());
                attachedVirtualMachineConfCollection.add(virtualMachineConfCollectionVirtualMachineConfToAttach);
            }
            service.setVirtualMachineConfCollection(attachedVirtualMachineConfCollection);
            Collection<ServiceInstance> attachedServiceInstanceCollection = new ArrayList<ServiceInstance>();
            for (ServiceInstance serviceInstanceCollectionServiceInstanceToAttach : service.getServiceInstanceCollection()) {
                serviceInstanceCollectionServiceInstanceToAttach = em.getReference(serviceInstanceCollectionServiceInstanceToAttach.getClass(), serviceInstanceCollectionServiceInstanceToAttach.getId());
                attachedServiceInstanceCollection.add(serviceInstanceCollectionServiceInstanceToAttach);
            }
            service.setServiceInstanceCollection(attachedServiceInstanceCollection);
            em.persist(service);
            if (component != null) {
                component.setService(service);
                component = em.merge(component);
            }
            for (Service serviceCollectionService : service.getServiceCollection()) {
                serviceCollectionService.getServiceCollection().add(service);
                serviceCollectionService = em.merge(serviceCollectionService);
            }
            for (Service serviceCollection1Service : service.getServiceCollection1()) {
                serviceCollection1Service.getServiceCollection().add(service);
                serviceCollection1Service = em.merge(serviceCollection1Service);
            }
            for (Activity activityCollectionActivity : service.getActivityCollection()) {
                activityCollectionActivity.getServiceCollection().add(service);
                activityCollectionActivity = em.merge(activityCollectionActivity);
            }
            for (VirtualMachineConf virtualMachineConfCollectionVirtualMachineConf : service.getVirtualMachineConfCollection()) {
                virtualMachineConfCollectionVirtualMachineConf.getServiceCollection().add(service);
                virtualMachineConfCollectionVirtualMachineConf = em.merge(virtualMachineConfCollectionVirtualMachineConf);
            }
            for (ServiceInstance serviceInstanceCollectionServiceInstance : service.getServiceInstanceCollection()) {
                Service oldIdServiceOfServiceInstanceCollectionServiceInstance = serviceInstanceCollectionServiceInstance.getIdService();
                serviceInstanceCollectionServiceInstance.setIdService(service);
                serviceInstanceCollectionServiceInstance = em.merge(serviceInstanceCollectionServiceInstance);
                if (oldIdServiceOfServiceInstanceCollectionServiceInstance != null) {
                    oldIdServiceOfServiceInstanceCollectionServiceInstance.getServiceInstanceCollection().remove(serviceInstanceCollectionServiceInstance);
                    oldIdServiceOfServiceInstanceCollectionServiceInstance = em.merge(oldIdServiceOfServiceInstanceCollectionServiceInstance);
                }
            }
            em.getTransaction().commit();
        } catch (Exception ex) {
            if (findService(service.getId()) != null) {
                throw new PreexistingEntityException("Service " + service + " already exists.", ex);
            }
            throw ex;
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    public void edit(Service service) throws IllegalOrphanException, NonexistentEntityException, Exception {
        EntityManager em = null;
        try {
            em = getEntityManager();
            em.getTransaction().begin();
            Service persistentService = em.find(Service.class, service.getId());
            Component componentOld = persistentService.getComponent();
            Component componentNew = service.getComponent();
            Collection<Service> serviceCollectionOld = persistentService.getServiceCollection();
            Collection<Service> serviceCollectionNew = service.getServiceCollection();
            Collection<Service> serviceCollection1Old = persistentService.getServiceCollection1();
            Collection<Service> serviceCollection1New = service.getServiceCollection1();
            Collection<Activity> activityCollectionOld = persistentService.getActivityCollection();
            Collection<Activity> activityCollectionNew = service.getActivityCollection();
            Collection<VirtualMachineConf> virtualMachineConfCollectionOld = persistentService.getVirtualMachineConfCollection();
            Collection<VirtualMachineConf> virtualMachineConfCollectionNew = service.getVirtualMachineConfCollection();
            Collection<ServiceInstance> serviceInstanceCollectionOld = persistentService.getServiceInstanceCollection();
            Collection<ServiceInstance> serviceInstanceCollectionNew = service.getServiceInstanceCollection();
            List<String> illegalOrphanMessages = null;
            if (componentNew != null && !componentNew.equals(componentOld)) {
                Service oldServiceOfComponent = componentNew.getService();
                if (oldServiceOfComponent != null) {
                    if (illegalOrphanMessages == null) {
                        illegalOrphanMessages = new ArrayList<String>();
                    }
                    illegalOrphanMessages.add("The Component " + componentNew + " already has an item of type Service whose component column cannot be null. Please make another selection for the component field.");
                }
            }
            if (illegalOrphanMessages != null) {
                throw new IllegalOrphanException(illegalOrphanMessages);
            }
            if (componentNew != null) {
                componentNew = em.getReference(componentNew.getClass(), componentNew.getId());
                service.setComponent(componentNew);
            }
            Collection<Service> attachedServiceCollectionNew = new ArrayList<Service>();
            for (Service serviceCollectionNewServiceToAttach : serviceCollectionNew) {
                serviceCollectionNewServiceToAttach = em.getReference(serviceCollectionNewServiceToAttach.getClass(), serviceCollectionNewServiceToAttach.getId());
                attachedServiceCollectionNew.add(serviceCollectionNewServiceToAttach);
            }
            serviceCollectionNew = attachedServiceCollectionNew;
            service.setServiceCollection(serviceCollectionNew);
            Collection<Service> attachedServiceCollection1New = new ArrayList<Service>();
            for (Service serviceCollection1NewServiceToAttach : serviceCollection1New) {
                serviceCollection1NewServiceToAttach = em.getReference(serviceCollection1NewServiceToAttach.getClass(), serviceCollection1NewServiceToAttach.getId());
                attachedServiceCollection1New.add(serviceCollection1NewServiceToAttach);
            }
            serviceCollection1New = attachedServiceCollection1New;
            service.setServiceCollection1(serviceCollection1New);
            Collection<Activity> attachedActivityCollectionNew = new ArrayList<Activity>();
            for (Activity activityCollectionNewActivityToAttach : activityCollectionNew) {
                activityCollectionNewActivityToAttach = em.getReference(activityCollectionNewActivityToAttach.getClass(), activityCollectionNewActivityToAttach.getId());
                attachedActivityCollectionNew.add(activityCollectionNewActivityToAttach);
            }
            activityCollectionNew = attachedActivityCollectionNew;
            service.setActivityCollection(activityCollectionNew);
            Collection<VirtualMachineConf> attachedVirtualMachineConfCollectionNew = new ArrayList<VirtualMachineConf>();
            for (VirtualMachineConf virtualMachineConfCollectionNewVirtualMachineConfToAttach : virtualMachineConfCollectionNew) {
                virtualMachineConfCollectionNewVirtualMachineConfToAttach = em.getReference(virtualMachineConfCollectionNewVirtualMachineConfToAttach.getClass(), virtualMachineConfCollectionNewVirtualMachineConfToAttach.getId());
                attachedVirtualMachineConfCollectionNew.add(virtualMachineConfCollectionNewVirtualMachineConfToAttach);
            }
            virtualMachineConfCollectionNew = attachedVirtualMachineConfCollectionNew;
            service.setVirtualMachineConfCollection(virtualMachineConfCollectionNew);
            Collection<ServiceInstance> attachedServiceInstanceCollectionNew = new ArrayList<ServiceInstance>();
            for (ServiceInstance serviceInstanceCollectionNewServiceInstanceToAttach : serviceInstanceCollectionNew) {
                serviceInstanceCollectionNewServiceInstanceToAttach = em.getReference(serviceInstanceCollectionNewServiceInstanceToAttach.getClass(), serviceInstanceCollectionNewServiceInstanceToAttach.getId());
                attachedServiceInstanceCollectionNew.add(serviceInstanceCollectionNewServiceInstanceToAttach);
            }
            serviceInstanceCollectionNew = attachedServiceInstanceCollectionNew;
            service.setServiceInstanceCollection(serviceInstanceCollectionNew);
            service = em.merge(service);
            if (componentOld != null && !componentOld.equals(componentNew)) {
                componentOld.setService(null);
                componentOld = em.merge(componentOld);
            }
            if (componentNew != null && !componentNew.equals(componentOld)) {
                componentNew.setService(service);
                componentNew = em.merge(componentNew);
            }
            for (Service serviceCollectionOldService : serviceCollectionOld) {
                if (!serviceCollectionNew.contains(serviceCollectionOldService)) {
                    serviceCollectionOldService.getServiceCollection().remove(service);
                    serviceCollectionOldService = em.merge(serviceCollectionOldService);
                }
            }
            for (Service serviceCollectionNewService : serviceCollectionNew) {
                if (!serviceCollectionOld.contains(serviceCollectionNewService)) {
                    serviceCollectionNewService.getServiceCollection().add(service);
                    serviceCollectionNewService = em.merge(serviceCollectionNewService);
                }
            }
            for (Service serviceCollection1OldService : serviceCollection1Old) {
                if (!serviceCollection1New.contains(serviceCollection1OldService)) {
                    serviceCollection1OldService.getServiceCollection().remove(service);
                    serviceCollection1OldService = em.merge(serviceCollection1OldService);
                }
            }
            for (Service serviceCollection1NewService : serviceCollection1New) {
                if (!serviceCollection1Old.contains(serviceCollection1NewService)) {
                    serviceCollection1NewService.getServiceCollection().add(service);
                    serviceCollection1NewService = em.merge(serviceCollection1NewService);
                }
            }
            for (Activity activityCollectionOldActivity : activityCollectionOld) {
                if (!activityCollectionNew.contains(activityCollectionOldActivity)) {
                    activityCollectionOldActivity.getServiceCollection().remove(service);
                    activityCollectionOldActivity = em.merge(activityCollectionOldActivity);
                }
            }
            for (Activity activityCollectionNewActivity : activityCollectionNew) {
                if (!activityCollectionOld.contains(activityCollectionNewActivity)) {
                    activityCollectionNewActivity.getServiceCollection().add(service);
                    activityCollectionNewActivity = em.merge(activityCollectionNewActivity);
                }
            }
            for (VirtualMachineConf virtualMachineConfCollectionOldVirtualMachineConf : virtualMachineConfCollectionOld) {
                if (!virtualMachineConfCollectionNew.contains(virtualMachineConfCollectionOldVirtualMachineConf)) {
                    virtualMachineConfCollectionOldVirtualMachineConf.getServiceCollection().remove(service);
                    virtualMachineConfCollectionOldVirtualMachineConf = em.merge(virtualMachineConfCollectionOldVirtualMachineConf);
                }
            }
            for (VirtualMachineConf virtualMachineConfCollectionNewVirtualMachineConf : virtualMachineConfCollectionNew) {
                if (!virtualMachineConfCollectionOld.contains(virtualMachineConfCollectionNewVirtualMachineConf)) {
                    virtualMachineConfCollectionNewVirtualMachineConf.getServiceCollection().add(service);
                    virtualMachineConfCollectionNewVirtualMachineConf = em.merge(virtualMachineConfCollectionNewVirtualMachineConf);
                }
            }
            for (ServiceInstance serviceInstanceCollectionOldServiceInstance : serviceInstanceCollectionOld) {
                if (!serviceInstanceCollectionNew.contains(serviceInstanceCollectionOldServiceInstance)) {
                    serviceInstanceCollectionOldServiceInstance.setIdService(null);
                    serviceInstanceCollectionOldServiceInstance = em.merge(serviceInstanceCollectionOldServiceInstance);
                }
            }
            for (ServiceInstance serviceInstanceCollectionNewServiceInstance : serviceInstanceCollectionNew) {
                if (!serviceInstanceCollectionOld.contains(serviceInstanceCollectionNewServiceInstance)) {
                    Service oldIdServiceOfServiceInstanceCollectionNewServiceInstance = serviceInstanceCollectionNewServiceInstance.getIdService();
                    serviceInstanceCollectionNewServiceInstance.setIdService(service);
                    serviceInstanceCollectionNewServiceInstance = em.merge(serviceInstanceCollectionNewServiceInstance);
                    if (oldIdServiceOfServiceInstanceCollectionNewServiceInstance != null && !oldIdServiceOfServiceInstanceCollectionNewServiceInstance.equals(service)) {
                        oldIdServiceOfServiceInstanceCollectionNewServiceInstance.getServiceInstanceCollection().remove(serviceInstanceCollectionNewServiceInstance);
                        oldIdServiceOfServiceInstanceCollectionNewServiceInstance = em.merge(oldIdServiceOfServiceInstanceCollectionNewServiceInstance);
                    }
                }
            }
            em.getTransaction().commit();
        } catch (Exception ex) {
            String msg = ex.getLocalizedMessage();
            if (msg == null || msg.length() == 0) {
                String id = service.getId();
                if (findService(id) == null) {
                    throw new NonexistentEntityException("The service with id " + id + " no longer exists.");
                }
            }
            throw ex;
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    public void destroy(String id) throws NonexistentEntityException {
        EntityManager em = null;
        try {
            em = getEntityManager();
            em.getTransaction().begin();
            Service service;
            try {
                service = em.getReference(Service.class, id);
                service.getId();
            } catch (EntityNotFoundException enfe) {
                throw new NonexistentEntityException("The service with id " + id + " no longer exists.", enfe);
            }
            Component component = service.getComponent();
            if (component != null) {
                component.setService(null);
                component = em.merge(component);
            }
            Collection<Service> serviceCollection = service.getServiceCollection();
            for (Service serviceCollectionService : serviceCollection) {
                serviceCollectionService.getServiceCollection().remove(service);
                serviceCollectionService = em.merge(serviceCollectionService);
            }
            Collection<Service> serviceCollection1 = service.getServiceCollection1();
            for (Service serviceCollection1Service : serviceCollection1) {
                serviceCollection1Service.getServiceCollection().remove(service);
                serviceCollection1Service = em.merge(serviceCollection1Service);
            }
            Collection<Activity> activityCollection = service.getActivityCollection();
            for (Activity activityCollectionActivity : activityCollection) {
                activityCollectionActivity.getServiceCollection().remove(service);
                activityCollectionActivity = em.merge(activityCollectionActivity);
            }
            Collection<VirtualMachineConf> virtualMachineConfCollection = service.getVirtualMachineConfCollection();
            for (VirtualMachineConf virtualMachineConfCollectionVirtualMachineConf : virtualMachineConfCollection) {
                virtualMachineConfCollectionVirtualMachineConf.getServiceCollection().remove(service);
                virtualMachineConfCollectionVirtualMachineConf = em.merge(virtualMachineConfCollectionVirtualMachineConf);
            }
            Collection<ServiceInstance> serviceInstanceCollection = service.getServiceInstanceCollection();
            for (ServiceInstance serviceInstanceCollectionServiceInstance : serviceInstanceCollection) {
                serviceInstanceCollectionServiceInstance.setIdService(null);
                serviceInstanceCollectionServiceInstance = em.merge(serviceInstanceCollectionServiceInstance);
            }
            em.remove(service);
            em.getTransaction().commit();
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    public List<Service> findServiceEntities() {
        return findServiceEntities(true, -1, -1);
    }

    public List<Service> findServiceEntities(int maxResults, int firstResult) {
        return findServiceEntities(false, maxResults, firstResult);
    }

    private List<Service> findServiceEntities(boolean all, int maxResults, int firstResult) {
        EntityManager em = getEntityManager();
        try {
            CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
            cq.select(cq.from(Service.class));
            Query q = em.createQuery(cq);
            if (!all) {
                q.setMaxResults(maxResults);
                q.setFirstResult(firstResult);
            }
            return q.getResultList();
        } finally {
            em.close();
        }
    }

    public Service findService(String id) {
        EntityManager em = getEntityManager();
        try {
            return em.find(Service.class, id);
        } finally {
            em.close();
        }
    }

    public int getServiceCount() {
        EntityManager em = getEntityManager();
        try {
            CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
            Root<Service> rt = cq.from(Service.class);
            cq.select(em.getCriteriaBuilder().count(rt));
            Query q = em.createQuery(cq);
            return ((Long) q.getSingleResult()).intValue();
        } finally {
            em.close();
        }
    }
    
}
